
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include "semantic.h"
#include "lexical.h"
#include "error.h"
#include "parser.h"
#include "gp_list.h"
#include "symbol.h"
#include "sym_table.h"
#include "common.h"

bool array_semantic_check(var_t *arr, int init_method, const char *str)
{
    if(!arr)
        return false;

    if(init_method == INIT_BY_LIST) {
        int list_len = get_list_len(&arr->arr_init_val);
        if(arr->ele_num == ARR_SIZE_UNKNOWN) {
            arr->ele_num = list_len;
            if(arr->is_ptr) {
                arr->size = 4 * list_len;
            } else {
                arr->size = (arr->type == INT) ? (4 * list_len) : list_len;	
            }
            
        } else if(arr->ele_num < list_len) {
            sem_err(EXCESS_ELEMENTS_IN_ARRAY_INIT, ERROR, arr->name, NULL);
            return false;
        } 
        gp_node_t *node;    
	    list_for_each_entry(node, &arr->arr_init_val, entry) {
            var_t *ele = node->addr;
            if(IS_BASE_CHAR(arr) && !IS_BASE_CHAR(ele)) {
                sem_err(ARRAY_INITIALIZE_BY_WRONG_TYPE, ERROR, arr->name, NULL);
                return false;
            }
		    
            if(IS_BASE_INT(arr) && !IS_BASE(ele)) { // int 兼容 char
                sem_err(ARRAY_INITIALIZE_BY_WRONG_TYPE, ERROR, arr->name, NULL);
                return false;
            }

            if(IS_GLOBAL(arr) && !ele->is_literal && !ele->pointing_to) {
                sem_err(INITIALIZER_ELEMENT_NOT_CONSTANT, ERROR, arr->name, NULL);
                return false;
            }
	    }
        return true;
    } else if(init_method == INIT_BY_STRING) {
        if(!str) 
            return false; // 不会到这里

        if(arr->type != CHAR) {
            sem_err(INT_ARRAY_INITIALIZE_BY_STRING, ERROR, arr->name, NULL);
            return false;
        }

        if(!IS_ARR(arr) && !IS_PTR(arr)) {
            sem_err(INT_ARRAY_INITIALIZE_BY_STRING, ERROR, arr->name, NULL);
            return false;
        }

        if(arr->ele_num == ARR_SIZE_UNKNOWN) {
            arr->ele_num = strlen(str) + 1;
            arr->size = arr->ele_num;
        }

        if(strlen(str) + 1 > arr->ele_num) {
            sem_err(INITIALIZER_STRING_TOO_LONG, ERROR, arr->name, NULL);
            return false;
        }          
        
        var_t *var = new_literal(str, STRING, parser_get_token_line_num());
        add_str(var);
        arr->init_val = var; 
        return true;            
    }
    return false; // 不会到这里
}

bool var_type_exact_match(var_t *var1, var_t *var2)
{
    assert(var1 && var2);
    return (var1->type == var2->type && 
            var1->is_ptr == var2->is_ptr &&
            var1->is_arr == var2->is_arr &&
            var1->ele_num == var2->ele_num);
   
}


/*
	检查类型是否可以转换
*/
bool var_type_compatible(var_t *var1, var_t *var2)
{
    assert(var1 && var2);

	// gcc int 和 char 可以互相赋值
	if(IS_BASE(var1) && IS_BASE(var2)) 
		return true;
	else if(!IS_BASE(var1) && !IS_BASE(var2)) // 都不是基本类型
		return var1->type == var2->type; // 只要求数组元素或者指针指向的类型相同
	else
		return false;
}


bool fun_return_type_check_ok(fun_t *fun, var_t *ret)
{
    if(TYPE_IS_VOID(fun)) {
        if(TYPE_IS_VOID(ret))
            return true;
        else 
            return false;
    } else if(!fun->is_ptr) { // 函数返回值是基本类型
        if(NOT_BASE(ret)) {
            return false;
        } else if(TYPE_IS_INT(fun)) {
            return true;
        } else if(TYPE_IS_CHAR(fun) && TYPE_IS_CHAR(ret)) {
            return true;
        } else {
            // warning: overflow in conversion from ‘int’ to ‘char’
            sem_err(OVERFLOW_IN_CONVERSION_FROM_INT_TO_CHAR, WARNING, ret->note, NULL);
            return true;
        }
            
    } else if(IS_PTR(fun)) {
        if(NOT_BASE(ret) && (fun->type == ret->type)) {
            return true;
        }else {
            return false;
        }
    }
        
    return false; // 不应该到这里
}

bool fun_called_type_check_ok(fun_t *fun, struct list_head *realargs)
{
    if(!fun)
        return false;
    
    if(!fun->para_list_head && !realargs) // 都没有参数
        return true;

    if(fun->para_list_head && list_empty(fun->para_list_head))
        return false; // 形式参数列表没有任何有效的参数,说明函数定义或声明有错，不执行函数调用语句

    if(realargs && list_empty(realargs)) {
         // 实参列表没有任何有效的参数
        sem_err(INCORRECT_TYPE_FOR_FUNCTION_ARGUMENT, ERROR, fun->name, (void *)fun);
        return false;
    }

    if(fun->para_len != get_list_len(realargs)) {
        sem_err(INCORRECT_TYPE_FOR_FUNCTION_ARGUMENT, ERROR, fun->name, (void *)fun);
        return false;
    }

	gp_node_t *node1, *node2;
	struct list_head *n1 = fun->para_list_head->next;
	struct list_head *n2 = realargs->next;
	
	int match = true;
	for(int i = 0; i < fun->para_len; ++i) {
		node1 = container_of(n1, gp_node_t, entry);
		node2 = container_of(n2, gp_node_t, entry);	
        var_t *param = (var_t *)node1->addr;
        var_t *real_param = (var_t *)node2->addr;

        if(!var_type_compatible(param, real_param)) {  // 类型不一致			
			match = false;  
			break;
		} 
		n1 = n1->next;
		n2 = n2->next;
	}
        
    if(!match) {
        sem_err(INCORRECT_TYPE_FOR_FUNCTION_ARGUMENT, ERROR, fun->name, (void *)fun);
    }
    
    return match;
}

// 用于声明和声明、声明和定义之间的检查。二者函数名一样
bool fun_semantic_check_ok(fun_t *fun1, fun_t *fun2)
{
	assert(fun1 && fun2);
	if((fun1->type != fun2->type) || (fun1->para_len != fun2->para_len) 
                || fun1->is_ptr != fun2->is_ptr)
		return false; // 返回类型不一样或者参数个数不一样

	if(!fun1->para_len) // 都没有参数
		return true;

	gp_node_t *node1, *node2;
	struct list_head *n1 = fun1->para_list_head->next;
	struct list_head *n2 = fun2->para_list_head->next;
	
	int conflict = 0;
	for(int i = 0; i < fun1->para_len; ++i) {
		node1 = container_of(n1, gp_node_t, entry);
		node2 = container_of(n2, gp_node_t, entry);	
        var_t *fun1_param = (var_t *)node1->addr;
        var_t *fun2_param = (var_t *)node2->addr;

        if(!var_type_exact_match(fun1_param, fun2_param)) {  // 类型不一致			
			conflict = 1;  
			break;
		} 
		n1 = n1->next;
		n2 = n2->next;
	}

	return !conflict;
}
